package com.awesome.auth.service.ganter;

import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory;
import org.springframework.security.oauth2.provider.token.AbstractTokenGranter;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;

/**
 *                     .::::.
 *                   .::::::::.
 *                  :::::::::::    佛主保佑、永无Bug
 *              ..:::::::::::'
 *            '::::::::::::'
 *              .::::::::::
 *         '::::::::::::::..
 *              ..::::::::::::.
 *           ``::::::::::::::::
 *             ::::``:::::::::'        .:::.
 *            ::::'   ':::::'       .::::::::.
 *         .::::'      ::::     .:::::::'::::.
 *        .:::'       :::::  .:::::::::' ':::::.
 *       .::'        :::::.:::::::::'      ':::::.
 *      .::'         ::::::::::::::'         ``::::.
 *  ...:::           ::::::::::::'              ``::.
 * ```` ':.          ':::::::::'                  ::::..
 *                   '.:::::'                    ':'````..
 * @version: V1.0
 * @author: qxw
 * @description: 创建自定义抽象令牌授予者
 *令牌授权者的接口
 * @data: 2020年04月11日 18:06
 * @ModifyDate: 2020年04月11日 18:06
 **/
public class CustomTokenGranter extends AbstractTokenGranter {
    private static final String GRANT_TYPE = "mini_app";
    private boolean allowRefresh;
    private Authentication authentication;

    public CustomTokenGranter(
            AuthorizationServerTokenServices tokenServices,
            ClientDetailsService clientDetailsService,
            Authentication authentication) {
        //在这个接口里，它会根据请求传递过来的grant_type去挑一个具体的实现来执行令牌生成的逻辑。
        super(tokenServices, clientDetailsService, new DefaultOAuth2RequestFactory(clientDetailsService), GRANT_TYPE);

        //Authorization封装的实际上是当前授权用户的一些信息，也就是谁在进行授权行为，Authorization里封装的就是谁的信息
        this.authentication = authentication;
    }

    @Override
    public OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest) {
        OAuth2AccessToken token = super.grant(grantType, tokenRequest);
        if (token != null) {
            DefaultOAuth2AccessToken noRefresh = new DefaultOAuth2AccessToken(token);
            if (!this.allowRefresh) {
                noRefresh.setRefreshToken((null));
            }
            token = noRefresh;
        }

        return token;
    }

  /**
   * @description TODO(这里用一句话描述这个方法的作用)
   * @author: qxw
   * @date: 2020/4/11 18:21
   *
   * OAuth2Request和Authorization这两个对象组合起来，会形成一个OAuth2Authorization对象，
   * 而这个最终产生的对象它的里面就包含了
   * 当前是哪个第三方应用在请求哪个用户以哪种授权模式（包括授权过程中的一些其他参数）进行授权，
   * 也就是这个对象会汇总之前的几个对象的信息都会封装到OAuth2Authorization这个对象中。   *
   *
   * @param client
   * @param tokenRequest
   * @return: org.springframework.security.oauth2.provider.OAuth2Authentication
   */
  @Override
  protected OAuth2Authentication getOAuth2Authentication(
      ClientDetails client, TokenRequest tokenRequest) {
        //不论采用哪种方式进行令牌的生成，在这个生成的过程中都会产生两个对象，一个是OAuth2Request

        OAuth2Request storedOAuth2Request = this.getRequestFactory().createOAuth2Request(client, tokenRequest);
        return new OAuth2Authentication(storedOAuth2Request, authentication);
    }

    public void setAuthentication(Authentication authentication) {
        //Authorization封装的实际上是当前授权用户的一些信息，也就是谁在进行授权行为，Authorization里封装的就是谁的信息
        this.authentication = authentication;
    }

    public void setAllowRefresh(boolean allowRefresh) {
        this.allowRefresh = allowRefresh;
    }
}
